package com.smp.dao.impl;

import com.smp.constant.Constant;
import com.smp.dao.IBlogRepository;
import com.smp.entry.BlogBean;
import com.smp.vo.BlogParam;
import com.smp.vo.PageInfo;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author: xiaoyu.fang
 * @date: 2020/8/23
 * @version: v1.0
 * @description:
 **/
@Component
public class BlogRepositoryImpl implements IBlogRepository<BlogBean, String> {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public List<BlogBean> queryByTags(String tag) {
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        if (!StringUtils.isEmpty(tag)) {
            nativeSearchQueryBuilder.withQuery(QueryBuilders.termQuery("tags", tag));
        }
        NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
        SearchHits<BlogBean> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, BlogBean.class);
        List<BlogBean> blogBeans = new ArrayList<>(searchHits.getSearchHits().size());
        searchHits.forEach(blogBeanSearchHit -> blogBeans.add(blogBeanSearchHit.getContent()));
        return blogBeans;
    }

    @Override
    public PageInfo<BlogBean> query(BlogParam param) {
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        if (!StringUtils.isEmpty(param.getKeyword())) {
            nativeSearchQueryBuilder.withQuery(QueryBuilders.multiMatchQuery(param.getKeyword(), "title", "content", "author"))
                    .withHighlightFields(new HighlightBuilder.Field("title").preTags(Constant.preTag).postTags(Constant.postTag),
                            new HighlightBuilder.Field("content").preTags(Constant.preTag).postTags(Constant.postTag).fragmentOffset(500).numOfFragments(0),
                            new HighlightBuilder.Field("author").preTags(Constant.preTag).postTags(Constant.postTag))
                    .withPageable(PageRequest.of(param.getPageNum() - 1, param.getPageSize())).withMinScore(5f)
                    .build();
        }

        SearchHits<BlogBean> searchHits = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), BlogBean.class);
        List<BlogBean> blogBeans = new ArrayList<>(searchHits.getSearchHits().size());
        searchHits.forEach(searchHit -> {
            Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
            searchHit.getContent().setTitle(highlightFields.get("title") == null ? searchHit.getContent().getTitle() : highlightFields.get("title").get(0));
            searchHit.getContent().setContent(highlightFields.get("content") == null ? searchHit.getContent().getContent() : highlightFields.get("content").get(0));
            searchHit.getContent().setAuthor(highlightFields.get("author") == null ? searchHit.getContent().getAuthor() : highlightFields.get("author").get(0));
            blogBeans.add(searchHit.getContent());
        });
        return new PageInfo<>(param.getPageNum(), param.getPageSize(), (int) searchHits.getTotalHits(), blogBeans);
    }

    @Override
    public List<BlogBean> queryNest(String name) {
        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchQuery("comments.name", name))
                .build();
        SearchHits<BlogBean> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, BlogBean.class);
        List<BlogBean> blogBeans = new ArrayList<>(searchHits.getSearchHits().size());
        searchHits.getSearchHits().forEach(blogBeanSearchHit -> blogBeans.add(blogBeanSearchHit.getContent()));
        return blogBeans;
    }

}
